using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
using OpenTelemetry.Exporter;
using OpenTelemetry.Instrumentation;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Serilog;
using Serilog.Core;
using OpenTelemetry.Exporter.Prometheus;

namespace Matrix.Configuration
{
    /// <summary>
    /// OpenTelemetry配置扩展
    /// 提供企业级可观测性能力
    /// </summary>
    public static class OpenTelemetryExtensions
    {
        /// <summary>
        /// 添加Matrix Configuration服务的OpenTelemetry支持
        /// </summary>
        public static IServiceCollection AddMatrixOpenTelemetry(
            this IServiceCollection services,
            IConfiguration configuration)
        {
            var otelConfig = configuration.GetSection("OpenTelemetry");
            var serviceName = otelConfig["ServiceName"] ?? "matrix-configuration";
            var serviceVersion = otelConfig["ServiceVersion"] ?? "1.0.0";
            var environment = otelConfig["Environment"] ?? "development";

            // 添加调试日志
            Console.WriteLine($"[DEBUG] 正在加载OpenTelemetry配置 - ServiceName: {serviceName}, Environment: {environment}");

            services.AddOpenTelemetry()
                .ConfigureResource(resource => resource
                    .AddService(serviceName, serviceVersion)
                    .AddAttributes(new Dictionary<string, object>
                    {
                        ["service.namespace"] = "matrix-foundation",
                        ["service.instance.id"] = Environment.MachineName,
                        ["deployment.environment"] = environment,
                        ["service.language"] = "dotnet",
                        ["service.version"] = serviceVersion
                    }))
                .WithTracing(builder => ConfigureTracing(builder, otelConfig))
                .WithMetrics(builder => ConfigureMetrics(builder, otelConfig));

            // 配置日志
            services.AddLogging(builder => builder.AddOpenTelemetry(logging =>
            {
                ConfigureLogging(logging, otelConfig);
            }));

            return services;
        }

        /// <summary>
        /// 配置链路追踪
        /// </summary>
        private static TracerProviderBuilder ConfigureTracing(
            TracerProviderBuilder builder,
            IConfigurationSection otelConfig)
        {
            var samplingRate = double.Parse(otelConfig["SamplingRate"] ?? "0.1", System.Globalization.CultureInfo.InvariantCulture);

            return builder
                // 配置采样策略
                .SetSampler(new TraceIdRatioBasedSampler(samplingRate))

                // ASP.NET Core追踪
                .AddAspNetCoreInstrumentation(options =>
                {
                    options.RecordException = true;
                    options.EnrichWithHttpRequest = (activity, request) =>
                    {
                        activity.SetTag("http.method", request.Method);
                        activity.SetTag("http.url", request.Path);
                        activity.SetTag("http.host", request.Host.ToString());
                        activity.SetTag("http.scheme", request.Scheme);
                    };
                    options.EnrichWithHttpResponse = (activity, response) =>
                    {
                        activity.SetTag("http.status_code", response.StatusCode);
                        activity.SetStatus(response.StatusCode < 400 ? ActivityStatusCode.Ok : ActivityStatusCode.Error);
                    };
                    options.Filter = HttpContext =>
                        !HttpContext.Request.Path.StartsWithSegments("/health", StringComparison.OrdinalIgnoreCase) &&
                        !HttpContext.Request.Path.StartsWithSegments("/metrics", StringComparison.OrdinalIgnoreCase) &&
                        !HttpContext.Request.Path.StartsWithSegments("/swagger", StringComparison.OrdinalIgnoreCase);
                })

                // HttpClient追踪
                .AddHttpClientInstrumentation(options =>
                {
                    options.RecordException = true;
                    options.EnrichWithHttpRequestMessage = (activity, request) =>
                    {
                        activity.SetTag("http.method", request.Method.ToString());
                        activity.SetTag("http.url", request.RequestUri?.ToString());
                    };
                    options.EnrichWithHttpResponseMessage = (activity, response) =>
                    {
                        activity.SetTag("http.status_code", (int)response.StatusCode);
                        activity.SetStatus(response.IsSuccessStatusCode ? ActivityStatusCode.Ok : ActivityStatusCode.Error);
                    };
                })

                // Entity Framework Core追踪
                .AddEntityFrameworkCoreInstrumentation(options =>
                {
                    options.SetDbStatementForText = true;
                    options.SetDbStatementForStoredProcedure = false;
                    options.EnrichWithIDbCommand = (activity, command) =>
                    {
                        activity.SetTag("db.name", command.Connection?.Database);
                        activity.SetTag("db.system", "postgresql");
                        activity.SetTag("db.statement_type", GetCommandType(command.CommandText));
                    };
                })

                // 自定义业务追踪源
                .AddSource("Matrix.Configuration")
                .AddSource("Matrix.Configuration.Cache")
                .AddSource("Matrix.Configuration.Repository")
                .AddSource("Matrix.Configuration.Service")

                // 导出配置
                .AddOtlpExporter(otlpOptions =>
                {
                    var endpoint = otelConfig["Collector:Endpoint"] ?? "http://localhost:4317";
                    otlpOptions.Endpoint = new Uri(endpoint);
                    otlpOptions.Protocol = OtlpExportProtocol.Grpc;

                    var authToken = otelConfig["Collector:AuthToken"];
                    if (!string.IsNullOrEmpty(authToken))
                    {
                        otlpOptions.Headers = $"x-auth-token={authToken}";
                    }
                });
        }

        /// <summary>
        /// 配置指标监控
        /// </summary>
        private static MeterProviderBuilder ConfigureMetrics(
            MeterProviderBuilder builder,
            IConfigurationSection otelConfig)
        {
            var metricsConfig = otelConfig.GetSection("Metrics");
            var prometheusEnabledRaw = metricsConfig["PrometheusExporter:Enabled"];
            var prometheusEnabled = prometheusEnabledRaw == "true" || prometheusEnabledRaw == "True";
            var prometheusEndpoint = metricsConfig["PrometheusExporter:Endpoint"] ?? "/metrics";

            // 添加调试日志（简化版本）
            Console.WriteLine($"[DEBUG] 配置Metrics - PrometheusEnabled原始值: '{prometheusEnabledRaw}', 解析后: {prometheusEnabled}, Endpoint: {prometheusEndpoint}");
            Console.WriteLine($"[DEBUG] Metrics配置存在: {metricsConfig.Exists()}, PrometheusExporter配置存在: {metricsConfig.GetSection("PrometheusExporter").Exists()}");

            var metricsBuilder = builder
                // HTTP客户端指标
                .AddHttpClientInstrumentation()

                // 自定义业务指标
                .AddMeter("Matrix.Configuration")
                .AddMeter("Matrix.Configuration.Cache")
                .AddMeter("Matrix.Configuration.Database")
                .AddMeter("Matrix.Configuration.Business");

            // 添加Prometheus HTTP导出器
            if (prometheusEnabled)
            {
                Console.WriteLine("[DEBUG] 正在添加Prometheus导出器");
                metricsBuilder.AddPrometheusExporter();
            }
            else
            {
                Console.WriteLine("[DEBUG] Prometheus导出器未启用");
            }

            // 添加OTLP导出器
            return metricsBuilder
                .AddOtlpExporter(otlpOptions =>
                {
                    var endpoint = otelConfig["Collector:Endpoint"] ?? "http://localhost:4317";
                    otlpOptions.Endpoint = new Uri(endpoint);
                    otlpOptions.Protocol = OtlpExportProtocol.Grpc;
                });
        }

        /// <summary>
        /// 配置日志聚合
        /// </summary>
        private static OpenTelemetryLoggerOptions ConfigureLogging(
            OpenTelemetryLoggerOptions logging,
            IConfigurationSection otelConfig)
        {
            logging.AddOtlpExporter(otlpOptions =>
            {
                var endpoint = otelConfig["Collector:Endpoint"] ?? "http://localhost:4317";
                otlpOptions.Endpoint = new Uri(endpoint);
                otlpOptions.Protocol = OtlpExportProtocol.Grpc;
            });

            return logging;
        }

        /// <summary>
        /// 配置Serilog增强
        /// </summary>
        public static IHostBuilder ConfigureMatrixLogging(this IHostBuilder hostBuilder)
        {
            return hostBuilder.UseSerilog((context, services, loggerConfiguration) =>
            {
                loggerConfiguration
                    .ReadFrom.Configuration(context.Configuration)
                    .ReadFrom.Services(services)
                    .Enrich.FromLogContext()
                    .Enrich.WithProperty("Application", "Matrix.Configuration")
                    .Enrich.WithProperty("Environment", context.HostingEnvironment.EnvironmentName)
                    .Enrich.WithProperty("Version", Assembly.GetExecutingAssembly().GetName().Version?.ToString())
                    .Enrich.WithProperty("MachineName", Environment.MachineName)
                    .Enrich.WithProperty("ProcessId", Environment.ProcessId)
                    .Enrich.WithProperty("ThreadId", Environment.CurrentManagedThreadId)
                    // .Enrich.WithOpenTelemetry() - 暂时移除，包版本不兼容

                    // 控制台输出（开发环境）
                    .WriteTo.Console(
                        outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] [{SourceContext}] [{TenantId}] [{UserId}] [{TraceId}] {Message:lj}{NewLine}{Exception}")

                    // 本地日志文件
                    .WriteTo.File(
                        "logs/matrix-configuration-.txt",
                        rollingInterval: RollingInterval.Day,
                        outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level:u3}] [{SourceContext}] [{TenantId}] [{UserId}] [{TraceId}] {Message:lj}{NewLine}{Exception}",
                        retainedFileCountLimit: 30,
                        formatProvider: System.Globalization.CultureInfo.InvariantCulture)

                    // OpenTelemetry输出 - 暂时移除，包版本不兼容
                    // .WriteTo.OpenTelemetry()

                    // 错误日志单独记录
                    .WriteTo.File(
                        "logs/matrix-configuration-errors-.txt",
                        rollingInterval: RollingInterval.Day,
                        restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Error,
                        outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level:u3}] [{SourceContext}] [{TenantId}] [{UserId}] [{TraceId}] {Message:lj}{NewLine}{Exception}",
                        retainedFileCountLimit: 30,
                        formatProvider: System.Globalization.CultureInfo.InvariantCulture);
            });
        }

        /// <summary>
        /// 获取数据库命令类型
        /// </summary>
        private static string GetCommandType(string commandText)
        {
            if (string.IsNullOrWhiteSpace(commandText))
                return "unknown";

            var normalizedCommand = commandText.Trim().ToUpperInvariant();

            if (normalizedCommand.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
                return "select";
            if (normalizedCommand.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase))
                return "insert";
            if (normalizedCommand.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase))
                return "update";
            if (normalizedCommand.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase))
                return "delete";
            if (normalizedCommand.StartsWith("CREATE", StringComparison.OrdinalIgnoreCase))
                return "create";
            if (normalizedCommand.StartsWith("ALTER", StringComparison.OrdinalIgnoreCase))
                return "alter";
            if (normalizedCommand.StartsWith("DROP", StringComparison.OrdinalIgnoreCase))
                return "drop";

            return "other";
        }
    }

    /// <summary>
    /// Matrix Configuration日志增强器
    /// </summary>
    public class MatrixLogEnricher : ILogEventEnricher
    {
        private readonly IServiceProvider _serviceProvider;

        public MatrixLogEnricher(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public void Enrich(Serilog.Events.LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
        {
            // 尝试从服务容器获取当前上下文信息
            using var scope = _serviceProvider.CreateScope();

            // 添加租户ID（仅ID，不包含具体租户信息）
            var currentTenant = scope.ServiceProvider.GetService<Volo.Abp.MultiTenancy.ICurrentTenant>();
            if (currentTenant?.IsAvailable == true)
            {
                var tenantId = propertyFactory.CreateProperty("TenantId", currentTenant.Id?.ToString() ?? "null");
                logEvent.AddPropertyIfAbsent(tenantId);
            }

            // 暂时移除用户ID获取，包版本不兼容
            // var currentUser = scope.ServiceProvider.GetService<Volo.Abp.Security.ICurrentUser>();
            // if (currentUser?.Id != null)
            // {
            //     var userId = propertyFactory.CreateProperty("UserId", currentUser.Id.ToString());
            //     logEvent.AddPropertyIfAbsent(userId);
            // }

            // 添加追踪信息
            var activity = Activity.Current;
            if (activity != null)
            {
                var traceId = propertyFactory.CreateProperty("TraceId", activity.TraceId.ToString());
                logEvent.AddPropertyIfAbsent(traceId);

                var spanId = propertyFactory.CreateProperty("SpanId", activity.SpanId.ToString());
                logEvent.AddPropertyIfAbsent(spanId);
            }
        }
    }
}